<?php

namespace support\process\crontab;

use app\model\system\CrontabTask;

use app\model\system\CrontabTaskLog;
use support\Db;
use Workerman\Crontab\Crontab;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

class Task
{
    const FORBIDDEN_STATUS = '0';
    const NORMAL_STATUS = '1';

    // URL任务
    public const URL_CRONTAB = '0';
    // SQL任务
    public const CLASS_CRONTAB = '1';
    //shell 任务
    public const SHELL_CRONTAB = '2';
    // 命令任务
    public const COMMAND_CRONTAB = '3';

    public function onWorkerStart()
    {

        $ids = $this->crontabInit();
        if (!empty($ids)) {
            foreach ($ids as $id) {
                $this->crontabRun($id);
            }
        }
    }


    /**
     * 初始化定时任务
     * @return void
     */
    private function crontabInit()
    {
        $crontabTaskModel = new CrontabTask();
        $ids = $crontabTaskModel->where('status', self::NORMAL_STATUS)
            ->orderBy('sort', 'desc')
            ->pluck('id')->toArray();
        return $ids;
    }

    /**
     * 创建定时器
     * @param $id
     */
    private function crontabRun($id)
    {
        $crontabTaskModel = new CrontabTask();
        $data = $crontabTaskModel
            ->where('id', $id)
            ->where('status', self::NORMAL_STATUS)
            ->first();
        $data = $data ? $data->toArray() : [];

        if (!$data) return true;

        switch ($data['type']) {
            case self::COMMAND_CRONTAB:
                new Crontab($data['frequency'], function () use ($data) {
                    echo date('Y-m-d H:i:s') . "\n";
                    $time = time();
                    $startTime = microtime(true);
                    $code = 0;
                    $result = true;
                    global $cli;
                    try {
                        system($data['shell']);
                    } catch (\Throwable $e) {
                        $result = false;
                        $code = 1;
                        $exception = $e->getMessage();

                    }
                    $this->writeln('执行定时器任务#' . $data['id'] . ' ' . $data['frequency'] . ' ' . $data['shell'], $result);
                    $endTime = microtime(true);
                    $this->updateRunning($data['id'], $time);
                    $this->crontabRunLog([
                        'sid' => $data['id'],
                        'command' => $data['shell'],
                        'output' => '',
                        'return_var' => $result,
                        'running_time' => round($endTime - $startTime, 6),
                        'create_time' => $time,
                        'update_time' => $time,
                    ]);

                });
                break;
        }

    }

    /**
     * 输出日志
     * @param $msg
     * @param bool $isSuccess
     */
    private function writeln($msg, bool $isSuccess)
    {
        echo 'worker:' . ' [' . date('Y-m-d H:i:s') . '] ' . $msg . ($isSuccess ? " [Ok] " : " [Fail] ") . PHP_EOL;
    }

    /**
     * 更新运行次数/时间
     * @param $id
     * @param $time
     * @return void
     */
    private function updateRunning($id, $time)
    {
        $crontabTaskModel = new CrontabTask();
        return $crontabTaskModel
            ->where('id', $id)
            ->where('status', self::NORMAL_STATUS)
            ->update(['last_running_time' => $time, 'running_times' => Db::raw('running_times +1'), 'update_time' => time()]);

    }

    /**
     * 记录执行日志
     * @param array $param
     * @return void
     */
    private function crontabRunLog(array $param)
    {
        $crontabTaskModel = new CrontabTaskLog();
        return $crontabTaskModel->insert($param);
    }
}
